package com.ozten.reboot;

import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JPanel;

import org.mozilla.javascript.Context;
import org.mozilla.javascript.EvaluatorException;
import org.mozilla.javascript.ImporterTopLevel;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;

import com.ozten.reboot.icasualty.Soldier;

public class RememberComponent extends JPanel {

	private static final long serialVersionUID = 1L;
	private List<Soldier> casualties;

	volatile boolean running = true;

	void stopRunning() {
		running = false;
	}

	Context cx;
	Scriptable scope = null;

	Graphics2D g2;
	public static final int FPS = 75; // Desired frames per second
	public int skipFrames;

	public RememberComponent() {
		this(null);
	}

	/**
	 * You must call {@link RememberComponent#release()} when finished showing this
	 * screen
	 * 
	 * @param casualties
	 */
	public RememberComponent(List<Soldier> casualties) {
		this.casualties = casualties;
		initialize();
	}

	public void initialize() {
		cx = Context.enter();
		scope = new ImporterTopLevel(cx, true);

		exposeJavaObject("FPS", FPS, scope);
		exposeJavaObject("casualties", casualties, scope);
		exposeJavaObject("canvas", this, scope);

		eval("src/com/ozten/reboot/setup.js");
		loadCasualties();
	}

	/**
	 * Mirror of creation through new keyword, release is used to tear down this
	 * object and must be called
	 */
	public void release() {
		org.mozilla.javascript.Context.exit();
	}

	void updateRenderSleep() {
		while (running) {
			long before = System.currentTimeMillis();
			update();
			doSkipFrames();
			render();
			// try {
			long elapsedTime = System.currentTimeMillis() - before;
			long sleepDuration = (1000 / FPS) - elapsedTime;
			//System.out.println(sleepDuration + " " + elapsedTime + " " + (1000 / FPS));
			if (sleepDuration <= 0) {
				skipFrames = (int) Math.abs(sleepDuration);
			}

			/*
			 * Thread.sleep(10); } catch (InterruptedException e) {
			 * e.printStackTrace(); }
			 */
		}

	}

	public void doSkipFrames() {
		if (skipFrames > FPS) {
			int skip = skipFrames / (1000 / FPS);
			skipFrames = skipFrames % (1000 / FPS);
			for (int i = 0; i < skip; i++) {
				update();
			}
		}
	}

	public void update() {
		try {

			String script = "src/com/ozten/reboot/update.js";
			if (new File(script).exists()) {
				Reader in = new FileReader(script);
				cx.evaluateReader(scope, in, script, 0, null);
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void loadCasualties() {
		try {
			String data = ICasualtiesReader.LOCAL_ICASUALTY_FEED;
			Reader dataIn = new FileReader(data);
			cx.evaluateReader(scope, dataIn, data, 0, null);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {

		}
	}

	void eval(String scriptFile) {
		try {

			if (new File(scriptFile).exists()) {
				Reader in = new FileReader(scriptFile);
				cx.evaluateReader(scope, in, scriptFile, 1, null);
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private Image buffer;

	public void render() {
		if (g2 == null) {
			buffer = createImage(getWidth(), getHeight());
			g2 = (Graphics2D) buffer.getGraphics();

			exposeJavaObject("g2", g2, scope);
		}

		try {
			String script = "src/com/ozten/reboot/remember.js";
			script = "src/com/ozten/reboot/render.js";
			if (new File(script).exists()) {
				Reader in = new FileReader(script);
				cx.evaluateReader(scope, in, script, 0, null);
			}
			long before = System.currentTimeMillis();
			long before2 = System.currentTimeMillis();
			getGraphics().drawImage(buffer, 0, 0, null);
			//System.out.println("short=" + (before2 - before) + " buffering takes " + (System.currentTimeMillis() - before2));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (EvaluatorException e) {
			e.printStackTrace(System.err);
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e1) {
				e1.printStackTrace();
			}
		} catch (org.mozilla.javascript.EcmaError e) {
			e.printStackTrace(System.err);
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e1) {
				e1.printStackTrace();
			}
		}

	}

	/* protected */void exposeJavaObject(String name, Object value,
			Scriptable scope) {
		ScriptableObject.putProperty(scope, name, Context
				.javaToJS(value, scope));
	}

	public static void main(String[] args) {
		RememberComponent play = new RememberComponent();

		JFrame win = new JFrame();

		win.setSize(Toolkit.getDefaultToolkit().getScreenSize().width - 100,
				Toolkit.getDefaultToolkit().getScreenSize().height - 100);
		win.add(play);
		win.setVisible(true);
		play.updateRenderSleep();

	}
}